/*	AirAttack class definition.
 *
*/

#include "AirAttack.h"

// AirAttack every minute or so
static const int AirAttackingInterval = 24*1;
AirAttack::AirAttack(std::string incName) : Behavior(incName),
									//designatedHealer(NULL),
									lastAirAttackFrame(-1)
{
	
}

void AirAttack::Enter()
{
	DEBUG_PRINT("AirAttack(%p) entering.\n", this);
}

void AirAttack::Execute()
{
	BWAPI::Position attackPosition(BB->GetAttackPosition());
	std::list<Base*>* EnemyBases = BB->GetEnemyBases();
	std::list<Base*>* MyBases = BB->GetBases();

	std::list<BWAPI::Unit*>* valkyrie = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Valkyrie);
	std::list<BWAPI::Unit*>* wraith = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Wraith);
	
	if(valkyrie || wraith)
	{	
		std::list<BWAPI::Unit*> AirArmy;

		if(valkyrie)
			AirArmy.insert(AirArmy.end(), valkyrie->begin(), valkyrie->end());
		if(wraith)
			AirArmy.insert(AirArmy.end(), wraith->begin(), wraith->end());

		for(std::list<BWAPI::Unit*>::iterator it = AirArmy.begin(); it != AirArmy.end(); it++)
		{
			if((*it)->getRemainingBuildTime()>0)
				continue;
			BWAPI::Unit* theUnit = (*it);
			//theUnit->attackMove(attackPosition);

			//head for the first enemy base:
			if(EnemyBases->size()>0 && ((theUnit->getHitPoints() >= 120 && theUnit->getType() == BWAPI::UnitTypes::Terran_Wraith) || (theUnit->getHitPoints() >= 200 && theUnit->getType() == BWAPI::UnitTypes::Terran_Valkyrie) ) && !theUnit->isBeingHealed())
			{
				Base* Ebase = EnemyBases->front();
				BWAPI::Position EBasePos, EBaseMovePos;
				std::list<UnitsRepairPos>::iterator RPUnitToRemove;
				std::list<DesignatedHealers>::iterator DHUnitToRemove;
				bool RPremoveUnit = false;
				bool DHremoveUnit = false;

				for(std::list<UnitsRepairPos>::iterator FRU = FoundRepairingPosition.begin(); FRU != FoundRepairingPosition.end(); FRU++)
				{
					if(theUnit->getID() == FRU->UnitID)
					{
						/*UnitToRemove->UnitID = FRU->UnitID;
						UnitToRemove->Pos = FRU->Pos;*/
						RPremoveUnit = true;
						RPUnitToRemove = FRU;
						break;
					}
				}
				if(RPremoveUnit)
					FoundRepairingPosition.erase(RPUnitToRemove);

				for(std::list<DesignatedHealers>::iterator HL = HealersList.begin(); HL != HealersList.end(); HL++)
				{
					if(theUnit->getID() == HL->AirCraftID)
					{
						DHremoveUnit = true;
						DHUnitToRemove = HL;
						break;
					}
				}
				if(DHremoveUnit)
					HealersList.erase(DHUnitToRemove);

				EBasePos.x() = (Ebase->GetBaseLocation().x()*TILE_SIZE);
				EBasePos.y() = (Ebase->GetBaseLocation().y()*TILE_SIZE);
				EBaseMovePos.x() = EBasePos.x() + (rand()%200);
				EBaseMovePos.y() = EBasePos.y() + (rand()%200);
				theUnit->attack(EBaseMovePos,true);

				if(theUnit->getDistance(EBasePos) < 700 && !theUnit->isAttacking()) //if I arrived at the enemy base.
				{	
					BWAPI::Unit* WorkerToAttack = findNearestEnemy(theUnit);//Find nearest worker.
					if(WorkerToAttack)
						theUnit->attack(WorkerToAttack,true); 
					else
						theUnit->attack(EBasePos,true);
				}
			}

			//Cloaking:
			if(theUnit->getHitPoints() >= 70 && theUnit->getHitPoints() < 120 && theUnit->getType() == BWAPI::UnitTypes::Terran_Wraith)
			{
				theUnit->cloak();
			}
			//Running back to the base, get repaired:
			if((theUnit->getHitPoints() < 120 && theUnit->getType() == BWAPI::UnitTypes::Terran_Wraith) || (theUnit->getHitPoints() < 200 && theUnit->getType() == BWAPI::UnitTypes::Terran_Valkyrie)) //If the aircraft getting killed, retreat.
			{
				Base* Mbase = MyBases->front();
				bool available = false;
				BWAPI::Position MBasePos;
				//MBasePos.x() = (Mbase->GetBaseLocation().x()*TILE_SIZE);
				//MBasePos.y() = (Mbase->GetBaseLocation().y()*TILE_SIZE);
				//theUnit->move(MBasePos);

				for(std::list<UnitsRepairPos>::iterator FRU = FoundRepairingPosition.begin(); FRU != FoundRepairingPosition.end(); FRU++)
				{
					if(theUnit->getID() == FRU->UnitID)
					{
						available = true;
						MBasePos = FRU->Pos;
					}
				}
				if(!available && theUnit->getHitPoints() < 70)
				{
					BWAPI::TilePosition pos = BuildPlacer->getBuildLocationNear(Mbase->GetBaseLocation(),BWAPI::UnitTypes::Terran_Supply_Depot);
					MBasePos.x() = (pos.x()*TILE_SIZE);
					MBasePos.y() = (pos.y()*TILE_SIZE);
					theUnit->move(MBasePos);
					
					UnitsRepairPos URP;
					URP.UnitID = theUnit->getID();
					URP.Pos = MBasePos;
					FoundRepairingPosition.insert(FoundRepairingPosition.end(),URP);
				}

				
				if(theUnit->getDistance(MBasePos) < 100) //if I arrived at my base.
				{
					bool FoundDH = false;
					BWAPI::Unit* designatedHealer;
					//if(!designatedHealer || !designatedHealer->exists() || designatedHealer->getDistance(theUnit) > 100)
					//{
					for(std::list<DesignatedHealers>::iterator HL = HealersList.begin(); HL != HealersList.end(); HL++)
					{
						if(theUnit->getID() == HL->AirCraftID)
						{
							FoundDH = true;
							designatedHealer = HL->designatedHealer;
							break;
						}
					}

					if(!FoundDH || designatedHealer->isConstructing())
					{
						designatedHealer = 0;

						std::list<BWAPI::Unit*>* scvs = Mbase->GetUnitsByType(BWAPI::UnitTypes::Terran_SCV);
						for(std::list<BWAPI::Unit*>::iterator SCV = scvs->begin(); SCV != scvs->end(); SCV++)
						{
							if((*SCV)->getRemainingBuildTime()>0)
								continue;
							if((*SCV)->isRepairing())
								continue;
							if((*SCV)->isConstructing())
								continue;
							if((*SCV)->isGatheringMinerals() || (*SCV)->isIdle())
							{
								designatedHealer = *SCV;
								break;
							}
						}
						if(designatedHealer && designatedHealer->isGatheringMinerals())
							designatedHealer->stop();
						
						DesignatedHealers DH;
						DH.AirCraftID = theUnit->getID();
						DH.designatedHealer = designatedHealer;
						DH.HasDesignatedHealer = true;
						HealersList.insert(HealersList.end(),DH);
					}
					if(designatedHealer)
					{
						designatedHealer->repair(theUnit);
					}
				}
			}
		}
	}

	// control cleanup
	control->FinishWithSuccess();

}

void AirAttack::Exit()
{
	DEBUG_PRINT("Exiting AirAttack behavior.\n");
}

bool AirAttack::CheckConditions()
{
	std::list<BWAPI::Unit*>* valkyries = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Valkyrie);
	std::list<BWAPI::Unit*>* wraiths = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Wraith);
	int totalSize = 0;
	if(valkyries)
		totalSize += valkyries->size();
	if(wraiths)
		totalSize += wraiths->size();

	if(totalSize < 3)
		return false;
	else
		return true;
}

BWAPI::Unit* AirAttack::findNearestEnemy(BWAPI::Unit* AirCraft)
{
	BWAPI::Unit* currentBest = 0;
	BWAPI::Position myPos = AirCraft->getPosition(), closePos;
	double bestDist=-1;
	for(std::set<BWAPI::Unit*>::const_iterator i=BWAPI::Broodwar->getAllUnits().begin();i!=BWAPI::Broodwar->getAllUnits().end();i++)
	{
		if(!(*i) || !(*i)->exists())
			continue;
		if ((*i)->getPlayer()->isEnemy(AirCraft->getPlayer()) && (*i)->getType().isWorker())
		{
			BWAPI::Position testPos = (*i)->getPosition();
			double d = testPos.getDistance(myPos);
			if(!currentBest) {
				currentBest = (*i);
				bestDist = d;
			}
			else {
				if(d<bestDist) {
					currentBest = (*i);
					bestDist = d;
				}
			}
		}
	}
	if(currentBest) {
		//BWAPI::Broodwar->sendText("Nearest enemy: %s", currentBest->getType().getName().c_str());
	}
	else {
		//BWAPI::Broodwar->sendText("No nearest enemy");
	}
	return currentBest;
}
